import { DataSource } from "typeorm";
import config from "@/config/config.default";
import {
  controller_metadata,
  router_metadata,
  router_Key,
  router_param_metadata,
  provide_metadata,
  inject_metadata,
  inject_entity_metadata,
  config_metadata,
} from "../constant";
import { RouteData, ControllerData } from "./types";

export class Container {
  public loadedMap = new Map(); // 初始化加载 存储到的 Map
  public moduleMap = new Map(); // 初始化加载  存储到的 Map
  private routerMap = new Map<string, any>(); // 最终合并存储的完整路由
  private controllerMap = new Map<string, any>(); // @Controller 获取路由前缀(prefix)
  private routerMethodMap = new Map<string, any>(); // 请求方法存储的 初始路由如：@Get @Post等  没有带路由前缀 prefix
  private routerParmaMap = new Map<string, any>(); // 路由请求参数 Map
  private typeormMap = new Map(); // typeorm 存储到Map
  private serviceMap = new Map(); // 存储service 注入
  private instanceMap = new Map();

  bindRouter(module: any, uuid: any) {
    const controller: ControllerData = Reflect.getMetadata(controller_metadata, module); // 获取装饰器 @Controller 前缀(prefix)
    if (controller) {
      // console.log("controller", controller);
      let routerData: RouteData[] = [];
      if (this.routerMap.has(router_Key)) {
        routerData = this.routerMap.get(router_Key);
      }
      Reflect.getMetadata(router_metadata, module)?.forEach((v: any, index: number) => {
        let routerParma = Reflect.getMetadata(router_param_metadata, module);
        routerData.push({ uuid, prefix: controller.prefix, ...v, requestData: routerParma[index] });
      });
      this.routerMap.set(router_Key, routerData);
    }
  }
  //  绑定 DataSource 实例到容器
  public bindDataSource(client: DataSource) {
    this.typeormMap.set("typeormName", client);
  }
  // 初始化绑定 typeorm entity  存储到容器
  public bindEntity(module: any, uuid: any) {
    const entity_metadata = Reflect.getMetadata(inject_entity_metadata, module);
    if (entity_metadata) {
      this.typeormMap.set(uuid, { uuid: uuid, entity: entity_metadata });
    }
  }
  // 获取 DataSource
  public getDataSource(dataSourceName: string) {
    return this.typeormMap.get(dataSourceName);
  }
  registerRepository(id: any) {
    const { module } = this.moduleMap.get(id);
    if (!module) return;
    const inject = Reflect.getMetadata(inject_metadata, module);
    let service: any[] = [];
    inject.forEach((item: any) => {
      if (item) {
        const CurrentService = this.moduleMap.get(item.uuid); // 这里查询到 service
        const entityModel = this.typeormMap.get(item.uuid);
        let ServiceInstance = new CurrentService.module();
        if (entityModel && Array.isArray(entityModel.entity)) {
          entityModel.entity.forEach((model: any) => {
            ServiceInstance[model.entityName] = this.typeormMap.get("typeormName").getRepository(model.entity);
            // console.log("DDitem", item);
          });
        }
        if (Reflect.getMetadata(config_metadata, CurrentService.module)) {
          ServiceInstance.config = config;
        }
        // console.log("ServiceInstance", CurrentService);
        service.push({ uuid: item.uuid, key: item.name, value: ServiceInstance });
      }
    });
    this.serviceMap.set("service", service);
    console.log("service");
  }
  // 注册到 service
  async registerService(id: any) {
    await this.registerRepository(id);
    await this.registerInstance(id);
  }
  // 注册到实例
  registerInstance(id: any) {
    const { module } = this.moduleMap.get(id);
    if (!module) return;
    const instance = new module();
    if (this.serviceMap.get("service")) {
      this.serviceMap.get("service").forEach((item: any) => {
        if (!instance[item.key]) {
          instance[item.key] = item.value;
        }
        // console.log("item", item);
      });
    }
    if (Reflect.getMetadata(config_metadata, module)) {
      instance.config = config;
    }
    // console.log("instance", instance);
    this.instanceMap.set(id, instance);
  }
  public getInstance(id: any) {
    return this.instanceMap.get(id);
  }
  getRouter() {
    return this.routerMap.get(router_Key) || [];
  }
  initLoad(module: Function) {
    const provide: any = Reflect.getMetadata(provide_metadata, module); //
    if (provide && provide.uuid) {
      // -----------------------------需要注入到容器的类---------------------------------------
      this.moduleMap.set(provide.uuid, { module, options: provide });
      // -----------------------------路由---------------------------------------
      this.bindRouter(module, provide.uuid);
      // -----------------------------数据库--------------------------------------
      this.bindEntity(module, provide.uuid);
    }
  }
}
